package com.yuba.front.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuba.common.core.constant.ActionTypes;
import com.yuba.common.core.exception.front.FrontException;
import com.yuba.common.core.utils.MapstructUtils;
import com.yuba.common.core.utils.StringUtils;
import com.yuba.common.mybatis.core.page.PageQuery;
import com.yuba.common.mybatis.core.page.TableDataInfo;
import com.yuba.front.domain.FrontMessage;
import com.yuba.front.domain.bo.FrontMessageBo;
import com.yuba.front.domain.vo.FrontMessageVo;
import com.yuba.front.mapper.CommentPostsMapper;
import com.yuba.front.mapper.FrontMessageMapper;
import com.yuba.front.service.IFrontMessageService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 用户消息通知Service业务层处理
 *
 * @author modakai
 * @date 2024-12-21
 */
@RequiredArgsConstructor
@Service
public class FrontMessageServiceImpl implements IFrontMessageService {

    private final FrontMessageMapper baseMapper;
    private final CommentPostsMapper commentPostsMapper;

    /**
     * 查询用户消息通知
     *
     * @param messageId 主键
     * @return 用户消息通知
     */
    @Override
    public FrontMessageVo queryById(Long messageId){
        return baseMapper.selectVoById(messageId);
    }

    /**
     * 分页查询用户消息通知列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 用户消息通知分页列表
     */
    @Override
    public TableDataInfo<FrontMessageVo> queryPageList(FrontMessageBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<FrontMessage> lqw = buildQueryWrapper(bo);
        Page<FrontMessageVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的用户消息通知列表
     *
     * @param bo 查询条件
     * @return 用户消息通知列表
     */
    @Override
    public List<FrontMessageVo> queryList(FrontMessageBo bo) {
        LambdaQueryWrapper<FrontMessage> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<FrontMessage> buildQueryWrapper(FrontMessageBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<FrontMessage> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getUserId() != null, FrontMessage::getUserId, bo.getUserId());
        lqw.eq(bo.getSenderId() != null, FrontMessage::getSenderId, bo.getSenderId());
        lqw.eq(StringUtils.isNotBlank(bo.getType()), FrontMessage::getType, bo.getType());
        lqw.eq(bo.getSourceId() != null, FrontMessage::getSourceId, bo.getSourceId());
        lqw.eq(StringUtils.isNotBlank(bo.getMeta()), FrontMessage::getMeta, bo.getMeta());
        lqw.eq(StringUtils.isNotBlank(bo.getValue()), FrontMessage::getValue, bo.getValue());
        lqw.eq(StringUtils.isNotBlank(bo.getReadFlag()), FrontMessage::getReadFlag, bo.getReadFlag());
        return lqw;
    }

    /**
     * 新增用户消息通知
     *
     * @param bo 用户消息通知
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(FrontMessageBo bo) {
        FrontMessage add = MapstructUtils.convert(bo, FrontMessage.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setMessageId(add.getMessageId());
        }
        return flag;
    }

    /**
     * 修改用户消息通知
     *
     * @param bo 用户消息通知
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(FrontMessageBo bo) {
        FrontMessage update = MapstructUtils.convert(bo, FrontMessage.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(FrontMessage entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除用户消息通知信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public List<Long> redCount(Long userId) {
        // 搜索用户拥有红点的消息类型
        List<FrontMessageVo> redVoList = baseMapper.selecRedList(userId);

        Map<String, Long> hash = new HashMap<>(16);
        long totalCount = 0;
        for (FrontMessageVo item : redVoList) {
            // 搜索
            LambdaQueryWrapper<FrontMessage> wrapper = new LambdaQueryWrapper<FrontMessage>()
                .eq(FrontMessage::getUserId, userId)
                .eq(FrontMessage::getType, item.getType())
                .eq(FrontMessage::getReadFlag, "N");
            Long count = baseMapper.selectCount(wrapper);
            // hash中存在值就相加
            if (hash.containsKey(item.getType())) {
                hash.put(item.getType(), hash.get(item.getType()) + count);
            } else {
                hash.put(item.getType(), count);
            }
            totalCount += count;
        }

        return List.of(
            totalCount,
            hash.getOrDefault(ActionTypes.COMMENT, 0L),
            hash.getOrDefault(ActionTypes.LIKE, 0L),
            hash.getOrDefault(ActionTypes.COLLECT, 0L)
        );
    }

    @Override
    public TableDataInfo<FrontMessageVo> pageList(PageQuery pageQuery, Long userId, String type) {
        // 校验type
        // 如果是 LIKE,COLLECT
        if ("LIKE,COLLECT".equalsIgnoreCase(type)) {
            // 如果是 LIKE,COLLECT 的就需要分别查询为 LIKE和COLLECT的消息
            List<String> types = Arrays.stream(type.split(",")).toList();
            Page<FrontMessageVo> likePage = baseMapper.pageList(pageQuery.build(), userId, types);

            return TableDataInfo.build(likePage);
        } else {
            HashSet<Long> likeCommentIds = commentPostsMapper.getLikeCommentIds(userId);
            Page<FrontMessageVo> page = baseMapper.pageList(pageQuery.build(), userId, List.of(type));
            page.getRecords().forEach(item -> item.setLikeCommentFlag(likeCommentIds.contains(item.getSourceId())));
            return TableDataInfo.build(page);
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void read(List<Long> ids) {

        Long count = baseMapper.updateReads(ids);
        if (count != ids.size()) {
            throw new FrontException("front.message.update.read.error");
        }
    }

    @Override
    public void save(FrontMessage frontMessage) {
        baseMapper.insert(frontMessage);
    }

    @Override
    public void removeByUserIdAndSenderIdAndSourceIdAndType(Long userId, Long senderId, Long sourceId, String type) {
        LambdaQueryWrapper<FrontMessage> wrapper = new LambdaQueryWrapper<FrontMessage>()
            .eq(FrontMessage::getUserId, userId)
            .eq(FrontMessage::getSenderId, senderId)
            .eq(FrontMessage::getSourceId, sourceId)
            .eq(FrontMessage::getType, type);
        baseMapper.delete(wrapper);
    }
}
